/**
 * COPYRIGHT HangZhou Trustway Technology Company Limited
 * All right reserved.
 */
package com.robam.cloud.common.util.wechat;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.robam.cloud.common.bean.authcenter.entity.WechatSignParam;
import com.robam.cloud.common.bean.restful.entity.ServiceException;
import com.robam.cloud.common.util.HttpUtils;
import com.robam.cloud.common.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @Description
 * @Author 薛铁琪
 * @CreateTime 2020-07-20 18:28
 * @Version 1.0
 */
@Slf4j
@Component
public class WechatUtil {


    private static final String INTERFACEURL = "https://api.weixin.qq.com/";
    private static final String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    private static final String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    private static final String imgUrl = "https://api.weixin.qq.com/cityservice/face/identify/getimage";
    private static final String mediaUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";

    /**
     * 根据authCode获取用户openId
     *
     * @param authCode
     * @return
     */
    public WechatUser getWechatUserId(String appid, String appsecret, String authCode) {
        String openidUrl = "sns/oauth2/access_token";
        String usermsgUrl = "sns/userinfo";

        Map<String, String> params = ImmutableMap.<String, String>builder()
                .put("appid", appid)
                .put("secret", appsecret)
                .put("code", authCode)
                .put("grant_type", "authorization_code")
                .build();

        //获取access_token, openid
        //返回参数jsonResult：access_token, expires_in, refresh_token, openid, scope
        String jsonOpenIdResult = HttpUtils.doGet(INTERFACEURL, openidUrl, null, params, 0, 0, null);
        log.debug("code={} result={}", authCode, jsonOpenIdResult);
        if (StringUtil.isEmpty(jsonOpenIdResult)) {
            throw new ServiceException("微信三方登录失败请重试");
        }
        JSONObject result = JSONObject.parseObject(jsonOpenIdResult);
        String openid = (String) result.get("openid");
        String access_token = (String) result.get("access_token");
        if (StringUtils.isEmpty(access_token)) {
            throw new ServiceException("微信三方登录失败请重试" + result.toJSONString());
        }
        params = ImmutableMap.<String, String>builder()
                .put("access_token", access_token)
                .put("openid", openid)
                .put("lang", "zh_CN")
                .build();
        String jsonUserMsgResult = HttpUtils.doGet(INTERFACEURL, usermsgUrl, null, params, 0, 0, null);
        result = JSONObject.parseObject(jsonUserMsgResult);
        WechatUser wechatUser = new WechatUser();
        wechatUser.setSubscribe((String) result.get("subscribe"));
        wechatUser.setOpenid((String) result.get("openid"));
        wechatUser.setNickname((String) result.get("nickname"));
        wechatUser.setSex(String.valueOf(result.get("sex")));
        wechatUser.setProvince((String) result.get("province"));
        wechatUser.setCity((String) result.get("city"));
        wechatUser.setCountry((String) result.get("country"));
        wechatUser.setHeadimgurl((String) result.get("headimgurl"));
        wechatUser.setUnionId((String) result.get("unionid"));
        wechatUser.setPrivilege(result.get("privilege").toString());
        return wechatUser;
    }

    public String getAccessToken(String appid, String appsecret) {
        String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
        log.info("requestUrl = {}", requestUrl);
        String res = null;
        try {
            res = HttpUtils.doGet(requestUrl, null);
        } catch (IOException e) {
            log.error("获取微信accesstoken异常{}", e);
            return null;
        }
        // 如果请求成功
        if (!StringUtils.isEmpty(res)) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(res);
                return jsonObject.getString("access_token");
            } catch (JSONException e) {
                log.error(e.getMessage());
            }
        }
        return null;
    }

    public String getTicket(String accessToken) {
        String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", accessToken);
        String res = null;
        try {
            res = HttpUtils.doGet(requestUrl, null);
        } catch (IOException e) {
            log.error("获取微信accesstoken异常{}", e);
            return null;
        }
        // 如果请求成功
        if (!StringUtils.isEmpty(res)) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(res);
                return jsonObject.getString("ticket");
            } catch (JSONException e) {
                log.error(e.getMessage());
            }
        }
        return null;
    }

    /**
     * 用于获取微信直接返回图片流的接收并转成base64字符串
     *
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return
     */
    public String httpRequestofBytes(String accessToken, String requestMethod, String outputStr) {
        String requestUrl = imgUrl + "?access_token=" + accessToken;
        HttpsURLConnection httpUrlConn = null;
        InputStream inputStream = null;
        String base64 = "";
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            httpUrlConn = (HttpsURLConnection) url
                    .openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式，防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成base64字符
            inputStream = httpUrlConn.getInputStream();
            byte[] data = new byte[inputStream.available()];
            inputStream.read(data);
            Base64.Encoder encoder = Base64.getEncoder();
            base64 = encoder.encodeToString(data);// 返回Base64编码过的字节数组字符串
            // 释放资源
            inputStream.close();
            httpUrlConn.disconnect();
        } catch (ConnectException ce) {
            log.error("Weixin server connection timed out.");
        } catch (Exception e) {
            log.error("https request error:{}", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                httpUrlConn.disconnect();
            } catch (IOException e) {
                log.error("httpUrlConn close error:{}", e);
            }
        }
        return base64;
    }


    public WechatSignParam sign(String appid, String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;

        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException error={}", e);
            return null;
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException error={}", e);
            return null;
        }

        WechatSignParam wechatSignParam = new WechatSignParam();
        wechatSignParam.setAppId(appid);
        wechatSignParam.setNonceStr(nonce_str);
        wechatSignParam.setSignature(signature);
        wechatSignParam.setTimestamp(timestamp);
        return wechatSignParam;
    }

    private String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    private String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    public String getMediaUrl(String access_token, String serverId) {
        return String.format(mediaUrl, access_token, serverId);
    }
}
